package org.huangrui.juc.source.locks;

import org.junit.Test;

import java.util.concurrent.locks.ReentrantLock;

/**
 * 可重入锁(又名递归锁)
 *
 * @Author hr
 * @Create 2024-04-02 03:25
 */
public class T04_ReEntryLock {
    final Object obj = new Object();
    static ReentrantLock lock = new ReentrantLock();
    public static void main(String[] args) {
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "\t -----come in 外");
            lock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + "\t -----come in 中");
                lock.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + "\t -----come in 内");
                } finally {
                    lock.unlock();
                }
            } finally {
                // 由于加锁次数和释放次数不一样，第二个线程始终无法获取到锁，导致一直在等待。
                // lock.unlock();// 正常情况，加锁几次就要解锁几次
            }
        }, "t").start();

        new Thread(() ->{
           lock.lock();
           try {
                 System.out.println(Thread.currentThread().getName()+"\t -----come in t1");
           }finally {
               lock.unlock();
           }
        },"t1").start();
    }



    /**
     * 测试可重入锁 同步方法
     */
    @Test
    public void testReSync(){
        T04_ReEntryLock entryLock = new T04_ReEntryLock();
        new Thread(entryLock::m1, "t1").start();
    }
    public synchronized void m1() {
        // 指的是可重复可递归调用的锁，在外层使用锁之后，在内层仍然可以使用，并且不发生死锁，这样的锁就叫做可重入锁。
        System.out.println(Thread.currentThread().getName() + "\t ----come in 1");
        m2();
        System.out.println(Thread.currentThread().getName() + "\t ----end m1");
    }

    public synchronized void m2() {
        System.out.println(Thread.currentThread().getName() + "\t ----come in 2");
        m3();
    }

    public synchronized void m3() {
        System.out.println(Thread.currentThread().getName() + "\t ----come in 3");
    }


    /**
     * 测试可重入锁 同步代码块
     */
    @Test
    public void entry01() {
        new Thread(() -> {
            synchronized (obj) {
                System.out.println(Thread.currentThread().getName() + "\t" + "外层调用");
                synchronized (obj) {
                    System.out.println(Thread.currentThread().getName() + "\t" + "中层调用");
                    synchronized (obj) {
                        System.out.println(Thread.currentThread().getName() + "\t" + "内层调用");
                    }
                }
            }
        }, "t1").start();
    }


    /**
     * 测试可重入锁 同步代码块
     */
    private static void reEntryM1() {
        final Object object = new Object();
        new Thread(() -> {
            synchronized (object) {
                System.out.println(Thread.currentThread().getName() + "\t ----外层调用");
                synchronized (object) {
                    System.out.println(Thread.currentThread().getName() + "\t ----中层调用");
                    synchronized (object) {
                        System.out.println(Thread.currentThread().getName() + "\t ----内层调用");
                    }
                }
            }
        }, "t1").start();
    }
}
